package io.openkunlun.javadsl;

import io.grpc.ForwardingServerCallListener;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;

/**
 * @author Srowen
 * @date Created on 2022/3/15
 * @description
 */
public final class DaprContext {

    public static final String METADATA = "dapr.metadata";

    public static <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(Context context, ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
        Context previous = context.attach();
        try {
            return new ContextualizedServerCallListener<>(next.startCall(call, headers), context);
        } finally {
            context.detach(previous);
        }
    }

    private static class ContextualizedServerCallListener<ReqT> extends ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT> {
        private final Context context;

        ContextualizedServerCallListener(ServerCall.Listener<ReqT> delegate, Context context) {
            super(delegate);
            this.context = context;
        }

        @Override
        public void onMessage(ReqT message) {
            Context previous = this.context.attach();

            try {
                super.onMessage(message);
            } finally {
                this.context.detach(previous);
            }

        }

        @Override
        public void onHalfClose() {
            Context previous = this.context.attach();

            try {
                super.onHalfClose();
            } finally {
                this.context.detach(previous);
            }

        }

        @Override
        public void onCancel() {
            Context previous = this.context.attach();

            try {
                super.onCancel();
            } finally {
                this.context.detach(previous);
            }

        }

        @Override
        public void onComplete() {
            Context previous = this.context.attach();

            try {
                super.onComplete();
            } finally {
                this.context.detach(previous);
            }

        }

        @Override
        public void onReady() {
            Context previous = this.context.attach();

            try {
                super.onReady();
            } finally {
                this.context.detach(previous);
            }

        }
    }

    private DaprContext() {
    }
}
